from rsa import RULESETPATH
from rsa.util import GLOBALVARS
from rsa.report import ReportManager
from rsa.loader.suite_loader import SuiteLoader 
from rsa.loader.rule_set_loader import DynamicRuleSetLoader
from robot.parsing.model import TestCase, Resource

class RSA(object):
    
    def __init__(self, rulesetpath=RULESETPATH):
        self.report = ReportManager()
        self.suite_loader = SuiteLoader()
        self.rule_set_factory = DynamicRuleSetLoader(rulesetpath)

        try:
            self.ruleSets = self.rule_set_factory.get_rule_sets()
        except Exception, e:
            self.ruleSets = []
            print "Warning: Rule sets were NOT loaded:", e
            
    def load_suite(self, path):
        """
        Returns a robot.parsing.model.TestData loaded from the argument path 
        """
        return self.suite_loader.load_suite(path)
    
    def include(self, rules):
        """
        Load only the specified rules.
        """
        if(rules):
            self.ruleSets.include(rules)
            
    def exclude(self, rules):
        """
        Ignore the rules specified.
        """
        if(rules):
            self.ruleSets.exclude(rules)
        
    def validate(self, element, ignore=None, use=None, callback=None):
        """
        Validates a robot structure. The validation can be made for robot structures or 
        file paths
        @param element: this parameter can be a robot structure or a file path to a robot project
        @return: a Report instance with all the violations found
        """
        self.include(use)
        self.exclude(ignore)
        self.validated_resources = []
        try:
            self.report.new_report(callback=callback,ignore=ignore, include=use)
            # load the test cases
            if (isinstance(element, str) or isinstance(element, unicode)):
                directorySuite = self.load_suite(element)
            else:
                directorySuite = element
            # load the symbols table
            symbols, resources = self.suite_loader.load_symbols_table(directorySuite)
            # apply the rules
            self.validate_directory(directorySuite, symbols, resources, self.ruleSets)
            # remove all the invalid violations
            self.remove_invalid_violations(self.report.report)
            # return errors found
            return self.report.report
        except Exception, e:
            print e
                    
    def validate_directory(self, suite, symbols, resources, ruleSets):
        """
        Validates a robot structure (TestCase, TestSuite or TestDirectory)
        """
        if(isinstance(suite, TestCase)):
            self.validate_test_case(suite, symbols, ruleSets)
        else:
            # If suite has resources instance and validate them
            if(len(suite.imports) > 0):
                for imp in suite.imports:
                    ruleSets.config(["UndefinedVariable"],"ignore")
                    self.validate_resource(imp, resources, ruleSets)
                    ruleSets.config(["UndefinedVariable"],"consider")
            # If suite has test cases validate every test case
            if(len(suite.testcase_table.tests) > 0):
                for test in suite.testcase_table.tests:
                    self.validate_test_case(test, symbols, ruleSets)
            if(len(suite.keyword_table.keywords) > 0):
                for keyword in suite.keyword_table.keywords:
                    self.validate_test_case(keyword, symbols, ruleSets)
            # Validate every child suite
            for child_suite in suite.children:
                self.validate_directory(child_suite, symbols, resources, ruleSets)
                
    def validate_resource(self, imp, symbols, ruleSets):
        """
        Validates a robot resource and all his keywords
        """
        array = imp.name.split("/")
        impname = array[len(array) - 1]
        if(isinstance(imp, Resource) and not impname in self.validated_resources):
            resource = self.suite_loader.instance_resource(imp)
            if(resource):
                for keyword in resource.keywords:
                    self.validate_test_case(keyword, symbols, ruleSets)
            self.validated_resources.append(impname)
                
    def validate_test_case(self, element, symbols, ruleSets):
        """
        Validates a robot test case
        """
        try:
            # Apply every rule to the test case/ keyword
            ruleSets.apply(element, symbols)
        except Exception, e:
            print 'Error while processing ' + element.name + ": " + e.message

    def remove_invalid_violations(self, report):
        """
        Remove all the invalid violations found during the analysis.
        """
        to_remove = []
        for violation in report:
            if(violation.rule.rule_id == "UndefinedVariable"):
                violation_elem = violation.element.lower()
                if(violation_elem in GLOBALVARS):
                    to_remove.append(violation)
        # remove all the invalid violations
        for violation in to_remove:
            report.remove_rule_violation(violation)